/*
 * Copyright (C) 2008 Universidade Federal de Campina Grande
 *  
 * This file is part of OurGrid. 
 *
 * OurGrid is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation, either version 3 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.ourgrid.acceptance.worker;

import static org.junit.Assert.assertFalse;

import org.junit.Before;
import org.junit.Test;
import org.ourgrid.acceptance.util.WorkerAcceptanceUtil;
import org.ourgrid.acceptance.util.worker.Req_004_Util;
import org.ourgrid.acceptance.util.worker.Req_079_Util;
import org.ourgrid.acceptance.util.worker.Req_087_Util;
import org.ourgrid.acceptance.util.worker.Req_088_Util;
import org.ourgrid.acceptance.util.worker.Req_090_Util;
import org.ourgrid.acceptance.util.worker.Req_092_Util;
import org.ourgrid.common.interfaces.Worker;
import org.ourgrid.common.interfaces.management.WorkerManagementClient;
import org.ourgrid.common.interfaces.to.WorkerStatus;
import org.ourgrid.reqtrace.ReqTest;
import org.ourgrid.worker.WorkerComponent;
import org.ourgrid.worker.WorkerConstants;

import br.edu.ufcg.lsd.commune.identification.ContainerID;
import br.edu.ufcg.lsd.commune.identification.DeploymentID;

@ReqTest(reqs="REQ079")
public class Req_079_Test extends WorkerAcceptanceTestCase {
	
	private DeploymentID peerID;
	private Req_004_Util req_004_Util = new Req_004_Util(getComponentContext());
	private Req_090_Util req_090_Util = new Req_090_Util(getComponentContext());
	private Req_092_Util req_092_Util = new Req_092_Util(getComponentContext());
	private Req_079_Util req_079_Util = new Req_079_Util(getComponentContext());
	private Req_087_Util req_087_Util = new Req_087_Util(getComponentContext());
	private Req_088_Util req_088_Util = new Req_088_Util(getComponentContext());
	
	@Before
	public void setUp() throws Exception {
		super.setUp();
		String peerPubKey = workerAcceptanceUtil.simulateAuthentication();
		
		peerID = new DeploymentID(new ContainerID("username", "server", "module", peerPubKey), "peer");
	}
	
	/**
	 *    1. Start a Worker with the idleness detector DISABLED;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer commands the Worker to work for the client with the public key "mgPublicKey1";
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPublicKey1]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    4. A client with the public key "mgPublicKey222" sends a startWork message;
	 *           * Verify if the following warn message was logged: The unknown client [clientID] tried to start the work of this Worker. This message was ignored. Unknown client public key: [mgPublicKey222].
	 *    5. The master peer commands the Worker to work for the client with the public key "publicKeyABC";
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [publicKeyABC]."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    6. A client with the public key "mgPublicKey1" sends a startWork message;
	 *           * Verify if the following warn message was logged: The unknown client [clientID] tried to start the work of this Worker. This message was ignored. Unknown client public key: [mgPublicKey1].
	 * 
	 */
	@ReqTest(test=" AT-079.1", reqs="REQ079")
	@Test public void test_at_079_1_UnknownClientTriesToStartWork() throws Exception {
		// Start worker without idleness detector
		WorkerComponent component = req_004_Util.startWorker();
		
		// Master peer sends setPeer to the worker
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		// The master peer commands the worker to work for a client [mgPubKey1]
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, "mgPubKey1");
		Worker worker1 = req_092_Util.beginAllocationCompleted(component, wmc);
		
		// Client [mgPubKey222] sends a startWork message - expect to ignore the message
		DeploymentID unknownMyGridID = new DeploymentID(new ContainerID("mgUserName", "mgServer", "mgModule", "mgPubKey222"),
				"myGrid");
		
		req_079_Util.startWorkByUnknownClient(component, worker1, "mgPubKey222", unknownMyGridID);
		
		// Master peer commands the worker to work for a client [pubKeyABC] - expect worker to be cleaned
		req_092_Util.workForMyGridOnAllocatedForMyGridWorker(component, wmc, "pubKeyABC");
		Worker worker222 = req_092_Util.beginAllocationCompleted(component, wmc);
		
		// Client [mgPubKey1] sends a startWork message - expect to ignore the message
		DeploymentID unknown2BrokerID = new DeploymentID(new ContainerID("mg2UserName", "mg2Server", "mg2Module", "mgPubKey1"),
			"myGrid2");
		
		req_079_Util.startWorkByUnknownClient(component, worker222, "mgPubKey1", unknown2BrokerID);
	} 
	
	/**
	 *    1. Start a Worker with the idleness detector DISABLED and the playpen root property set to a read-only directory;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer commands the Worker to work for the client with the public key "mgPublicKey1";
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPublicKey1]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    4. A client with the public key "mgPublicKey1" sends a startWork message;
	 *           * Verify if the following error message was logged: The client [clientID] tried to start the work of this Worker, but the playpen directory [playpenDir] cannot be created.
	 *           * Expect the Worker to send the client an error occurred message with the IO_ERROR type
	 * 
	 */
	@ReqTest(test=" AT-079.2", reqs="REQ079")
	@Test public void test_at_079_2_ClientStartsWorkWithError() throws Exception {
		// Creating read-only playpen root directory
		String invalidPlaypen = WorkerAcceptanceUtil.DEF_INVALID_PLAYPEN_ROOT_PATH;
		WorkerAcceptanceUtil.createDirectory(invalidPlaypen, true);
		
		// Start worker without idleness detector
		WorkerComponent component = req_004_Util.startWorker(false, true, false);
		
		// Master peer sends setPeer to the worker
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		// Master peer commands the worker to work for a client [mgPubKey1]
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, "mgPubKey1");
		Worker worker = req_092_Util.beginAllocationCompleted(component, wmc);
		
		// Client [mgPubKey1] sends a startWork message - expect an error to be logged
		DeploymentID brokerID = new DeploymentID(new ContainerID("mgUserName", "mgServer", "mgModule", "mgPubKey1"),
				"myGrid");
		
		req_079_Util.startWorkWithPlaypenError(component, worker, brokerID, invalidPlaypen);
	}
	
	/**
	 *    1. Start a Worker with the idleness detector DISABLED and the playpen root property set to a read-write directory;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer commands the Worker to work for the client with the public key "mgPublicKey1";
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPublicKey1]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    4. A client with the public key "mgPublicKey1" sends a startWork message;
	 *           * Verify if the following info message was logged: Worker is ready to start working for client [ClientID1].
	 *           * Expect the Worker to send the client a Worker is Ready message
	 *    5. The master peer commands the Worker to work for the client with the public key "mgPublicKey222";
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPublicKey222]."
	 *           * Verify if the following debug message was logged: "Cleaning worker."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    6. A client with the public key "mgPublicKey222" sends a startWork message;
	 *           * Verify if the following info message was logged: Worker is ready to start working for client [ClientID2].
	 *           * Expect the Worker to send the client a Worker is Ready message
	 *    7. A client with the public key "mgPublicKey222", with the same ID, sends a startWork message;
	 *           * Verify if the following info message was logged: Worker is ready to start working for client [ClientID2].
	 *           * Verify if the following debug message was logged: "Cleaning worker."
	 *           * Expect the Worker to send the client a Worker is Ready message
	 *    8. A client with the public key "mgPublicKey222", but from a different location, sends a startWork message;
	 *           * Verify if the following info message was logged: Worker is ready to start working for client [ClientID3].
	 *           * Verify if the following debug message was logged: "Cleaning worker."
	 *           * Expect the Worker to send the client a Worker is Ready message
	 *    9. Pause the Worker;
	 *           * Verify if the following info message was logged: "Worker has been PAUSED."
	 *           * Verify if the following debug message was logged: "Cleaning Worker."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_MYGRID to OWNER."
	 *           * Expect the Worker to send the peer a status changed message, with the OWNER status
	 *   10. Verify if the WORKER object is NOT bound
	 *   11. Resume the Worker;
	 *           * Verify if the following info message was logged: "Worker has been RESUMED."
	 *           * Verify if the following debug message was logged: "Status changed from OWNER to IDLE."
	 *           * Verify if the ControlClient received the operation succeed message
	 *   12. Verify if the WORKER object is NOT bound
	 * 
	 */
	@ReqTest(test=" AT-079.3", reqs="REQ079")
	@Test public void test_at_079_3_ClientStartsWorkWithSuccess() throws Exception {
		// Creating read-write playpen root directory
		WorkerAcceptanceUtil.createDirectory(WorkerAcceptanceUtil.DEF_PLAYPEN_ROOT_PATH, false);
		
		// Start worker without idleness detector
		WorkerComponent component = req_004_Util.startWorker();
		
		// Master peer sends setPeer to the worker
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		// The master peer commands the worker to work for a client [mgPubKey1]
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, "mgPubKey1");
		Worker worker1 = req_092_Util.beginAllocationCompleted(component, wmc);
		
		// Client [mgPubKey1] sends a startWork message - expect an info to be logged
		DeploymentID brokerID = new DeploymentID(new ContainerID("mgUserName", "mgServer", "mgModule", "mgPubKey1"),
				"myGrid");
		
		req_079_Util.startWorkSuccessfully(component, worker1, brokerID);
		
		// The master peer commands the worker to work for a client [mgPubKey222] - expect worker to be cleaned
		req_092_Util.workForMyGridOnAllocatedForMyGridWorker(component, wmc, "mgPubKey222");
		Worker worker222 = req_092_Util.beginAllocationCompleted(component, wmc);
		
		// Client [mgPubKey222] sends a startWork message - expect an info to be logged
		DeploymentID broker2ID = new DeploymentID(new ContainerID("mg2UserName", "mg2Server", "mg2Module", "mgPubKey222"),
				"myGrid2");
		
		req_079_Util.startWorkSuccessfully(component, worker222, broker2ID);
		
		// Client [mgPubKey222] sends a startWork message again - expect an info to be logged
		req_079_Util.startWorkSuccessfullyCleaning(component, worker222, broker2ID);
		
		// Client [mgPubKey222] sends a startWork message with another ObjectID - expect an info to be logged
		DeploymentID broker3ID = new DeploymentID(new ContainerID("mg3UserName", "mg3Server", "mg3Module", "mgPubKey222"),
			"myGrid3");
		
		req_079_Util.startWorkSuccessfullyCleaning(component, worker222, broker3ID);
		
		// Pause the worker - expect worker to be cleaned
		req_087_Util.pauseAllocatedForMyGridWorker(component, wmc);
		
		// Verify if the worker object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		// Resume the worker
//		TODO wmc = null ? req_088_Util.resumeOwnerWorker(component);
		req_088_Util.resumeOwnerWorker(wmc, component);
		
		// Verify if the worker object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
	}
	
}